package com.flower.aspect;

import com.alibaba.fastjson.JSON;
import com.flower.annotation.Log;
import com.flower.domain.entity.SysLog;
import com.flower.service.LogService;
import com.flower.utils.IpUtil;
import com.flower.utils.UserContext;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Autowired
    private LogService logService;

    // 配置切入点
    @Pointcut("@annotation(com.flower.annotation.Log)")
    public void logPointCut() {}

    // 配置环绕通知
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        
        try {
            // 执行方法
            Object result = point.proceed();
            // 执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            // 保存日志
            saveLog(point, time, true, null);
            return result;
        } catch (Exception e) {
            // 保存异常日志
            saveLog(point, System.currentTimeMillis() - beginTime, false, e.getMessage());
            throw e;
        }
    }

    /**
     * 保存日志
     */
    private void saveLog(ProceedingJoinPoint joinPoint, long time, boolean status, String errorMsg) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            SysLog sysLog = new SysLog();
            
            // 获取Log注解
            Log logAnnotation = method.getAnnotation(Log.class);
            if (logAnnotation != null) {
                sysLog.setName(logAnnotation.name());
            }

            // 获取请求相关信息
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            
            // 设置IP地址
            sysLog.setIp(IpUtil.getIpAddr(request));
            
            // 设置请求方法
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = method.getName();
            sysLog.setMethod(className + "." + methodName + "()");

            // 设置请求参数
            if (logAnnotation.saveParams()) {
                Object[] args = joinPoint.getArgs();
                // 处理参数，过滤掉MultipartFile类型
                Object[] filteredArgs = Arrays.stream(args)
                    .map(arg -> {
                        if (arg instanceof MultipartFile) {
                            MultipartFile file = (MultipartFile) arg;
                            return "文件: " + file.getOriginalFilename() + " (大小: " + file.getSize() + " bytes)";
                        }
                        return arg;
                    })
                    .toArray();
                String params = JSON.toJSONString(filteredArgs);
                sysLog.setParams(params);
            }

            // 设置操作状态
            sysLog.setStatus(status);
            
            // 设置错误消息
            sysLog.setErrorMsg(errorMsg);
            
            // 设置操作时间
            sysLog.setCreateTime(new Date());
            
            // 设置消耗时间
            sysLog.setCostTime(time);

            // 设置操作用户(从token中获取)
            String frontendType = UserContext.getFrontendType();
            Long userId = UserContext.getUserId();
            String username = userId + "(" + frontendType + ")" ; // 这里需要从token中获取当前登录用户
            sysLog.setUsername(username);

            // 保存系统日志
            logService.save(sysLog);
        } catch (Exception e) {
            log.error("保存系统日志失败", e);
        }
    }
} 